using System;
using System.Collections.Generic;
using System.Text.RegularExpressions;
using UnityEngine;


namespace Framework
{
    public class ShowColor
    {
        public bool Enabled;
        public Color32 Color;
    }
    public class GameObjectFieldItemNameProvider
    {
        public GameObjectFieldItemNameProvider() { }
        public virtual string GetName(string name, string type)
        {
            int dotId = type.LastIndexOf(".");
            if (dotId != -1)
            {
                type = type.Substring(dotId + 1);
            }
            return string.Format("{0}_{1}", name, type);
        }
        public virtual void GetShowColor(string type, ShowColor color)
        {

        }
    }
    [Serializable]
    public class GameObjectFieldItem
    {
        private static GameObjectFieldItemNameProvider _nameProvider;
        private static ShowColor _showColor = new ShowColor();
#if UNITY_EDITOR
        static GameObjectFieldItem()
        {
            var typeList = GetTypeNames(typeof(GameObjectFieldItemNameProvider), new string[] { "Assembly-CSharp-Editor" });
            foreach (var item in typeList)
            {
                if (System.Activator.CreateInstance(item) is GameObjectFieldItemNameProvider provider)
                {
                    _nameProvider = provider;
                    break;
                }
            }
        }
#endif
        private static System.Type[] GetTypeNames(System.Type typeBase, string[] assemblyNames)
        {
            List<System.Type> typeNames = new();
            foreach (string assemblyName in assemblyNames)
            {
                System.Reflection.Assembly assembly = System.Reflection.Assembly.Load(assemblyName);
                if (assembly == null)
                {
                    continue;
                }
                System.Type[] types = assembly.GetTypes();
                foreach (System.Type type in types)
                {
                    if (type.IsClass && !type.IsAbstract && typeBase.IsAssignableFrom(type))
                    {
                        typeNames.Add(type);
                    }
                }
            }
            return typeNames.ToArray();
        }

        public UnityEngine.Object Value;
        public string Name;
        public string Type;
        public string GetFieldName()
        {
            string fieldName;
            if (string.IsNullOrEmpty(Type))
            {
                this.Type = "GameObject";
            }
            if (_nameProvider != null)
            {
                fieldName = _nameProvider.GetName(this.Name, this.Type);
            }
            else
            {
                fieldName = GetKey(this.Name, GetShortType());
            }
            bool isValid = Regex.IsMatch(fieldName, @"^[a-zA-Z_][a-zA-Z0-9_]*$");
            if (isValid)
            {
                return fieldName;
            }
            Debug.LogErrorFormat("名称不合法 {0}", fieldName);

            return "_fix" + (Type + ":" + Name).GetHashCode();
        }
        public GameObject GetGameObject()
        {
            GameObject self = null;
            if (Value is GameObject goa)
            {
                self = goa;
            }
            else
            {
                if (Value is Component comp)
                {
                    self = comp.gameObject;
                }
            }
            return self;
        }
        public GameObjectFields GetOwner()
        {
            var self = GetGameObject();
            var f = self.GetComponentInParent<GameObjectFields>();
            if (f.gameObject == self)
            {
                return f.transform.parent.gameObject.GetComponentInParent<GameObjectFields>();
            }
            return f;
        }
        public string GetShortType()
        {
            string type = Type;
            int dotId = type.LastIndexOf(".");
            if (dotId != -1)
            {
                type = type.Substring(dotId + 1);
            }
            return type;
        }

        private static string GetKey(string name, string type)
        {
            return string.Format("{0}_{1}", FormatName(name), type);
        }
        public static string FormatName(string name)
        {
            return name.Replace(" ", "_").Replace("(", "").Replace(")", "");
        }

    }
    [DisallowMultipleComponent]
    public class GameObjectFields : MonoBehaviour
    {
        [SerializeField]
        [HideInInspector]
        public List<GameObjectFieldItem> FieldItems;
        private Dictionary<string, GameObjectFieldItem> _map;
        public void Add(GameObjectFieldItem value)
        {
            var k = value.GetFieldName();
            if (FieldItems == null)
            {
                FieldItems = new List<GameObjectFieldItem>();
            }
            foreach (var item in FieldItems)
            {
                if (item.GetFieldName() == k)
                {
                    return;
                }
            }
            FieldItems.Add(value);
#if UNITY_EDITOR
            Check(true);
#endif
        }

#if UNITY_EDITOR
        public bool Exist(GameObject value, string type)
        {
            if (FieldItems == null) return false;
            foreach (var item in FieldItems)
            {
                if (item.Type == type)
                {
                    if (item.Value is GameObject goa)
                    {
                        if (goa == value)
                        {
                            return true;
                        }
                    }
                    else
                    {
                        if ((item.Value as Component).gameObject == value)
                        {
                            return true;
                        }
                    }
                }
            }
            return false;
        }
        public void Check(bool modify = false)
        {
            if (FieldItems == null) return;
            var len = FieldItems.Count;
            var map = new Dictionary<string, int>();

            for (int i = 0; i < len; i++)
            {
                var item = FieldItems[i];
                if (item.Value == null)
                {
                    FrameworkLog.LogErrorFormat("第 {0} 项无效", i);
                    continue;
                }
                if (string.IsNullOrEmpty(item.Type))
                {
                    FrameworkLog.LogErrorFormat("第 {0} 类型为空", i);
                    continue;
                }
                if (item.GetOwner() != this)
                {
                    item.Value = null;
                    FrameworkLog.LogErrorFormat("第 {0} 归属有问题", i);
                }
                var k = item.GetFieldName();
                if (map.ContainsKey(k))
                {
                    FrameworkLog.LogErrorFormat("第 {0} 项与第 {1} 项重复", i, map[k]);
                    if (modify)
                    {
                        item.Value = null;
                    }
                    continue;
                }
                else
                {
                    map.Add(k, i);
                }
            }
            if (modify)
            {
                while (len-- > 0)
                {
                    var item = FieldItems[len];
                    if (item.Value == null)
                    {
                        FieldItems.RemoveAt(len);
                    }
                }
                UnityEditor.AssetDatabase.SaveAssetIfDirty(this.gameObject);
            }
            //FieldItems.Sort(sort);
            UnityEditor.EditorUtility.SetDirty(this.gameObject);
        }

        public string[] BuildScriptFields()
        {
            var len = FieldItems.Count;
            string[] lines = new string[len];
            for (var i = 0; i < len; i++)
            {
                var item = FieldItems[i];
                lines[i] = string.Format("private {0} {1};", item.Type, item.GetFieldName());
            }
            return lines;
        }
        public string[] BuildScriptParse()
        {
            var len = FieldItems.Count;
            string[] lines = new string[len];
            for (var i = 0; i < len; i++)
            {
                var item = FieldItems[i];
                lines[i] = string.Format("this.{1} = ({0})value.FieldItems[{2}].Value;", item.Type, item.GetFieldName(), i);
            }
            return lines;
        }
        [ContextMenu("复制代码")]
        public void CopyCode()
        {
            var lst = BuildScriptFields();
            string txt = string.Empty;
            for (int i = 0; i < lst.Length; i++)
            {
                txt += "\t" + lst[i] + "\n";
            }
            txt += "\tprotected void InjectFields(GameObjectFields value)\n\t{\n";

            lst = BuildScriptParse();
            for (int i = 0; i < lst.Length; i++)
            {
                txt += "\t\t" + lst[i] + "\n";
            }
            txt += "\t}";
            TextEditor textEd = new TextEditor();
            textEd.text = txt;
            textEd.OnFocus();
            textEd.Copy();
        }
#endif
    }

}